import { forwardRef, HttpException, HttpStatus, Inject, Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { User } from './entities/user.entity';
import {
  AddUserRolesDto,
  CreateUserDto,
  GetUserDto,
  RegisterUserDto,
  UpdatePasswordDto,
  UpdateUserDto,
} from '@/modules/user/dto/dto';
import { RedisService } from '@/shared/redis.service';
import { md5 } from '@/utils/MD5';
import { Role } from '@/modules/role/entities/role.entity';
import { Permission } from '@/modules/permission/entities/permission.entity';
import { PermissionService } from '@/modules/permission/permission.service';
import { CustomException, ErrorCode } from '@/common/exceptions/custom.exception';

@Injectable()
export class UserService {
  private logger = new Logger();

  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
    // 注入角色表
    @InjectRepository(Role)
    private roleRepository: Repository<Role>,
    // 注入权限表
    @InjectRepository(Permission)
    private permissionRepository: Repository<Permission>,
    private redisService: RedisService,
    @Inject(forwardRef(() => PermissionService))
    private readonly permissionService: PermissionService,
  ) {}

  async register(user: RegisterUserDto) {
    const captcha = await this.redisService.get(`captcha_${user.email}`);

    if (!captcha) {
      throw new HttpException('验证码已失效', HttpStatus.BAD_REQUEST);
    }

    if (user.captcha !== captcha) {
      throw new HttpException('验证码不正确', HttpStatus.BAD_REQUEST);
    }

    const newUser = new User();
    newUser.username = this.generateRandomUsername();
    newUser.nickName = this.generateRandomNickName();
    newUser.password = md5(user.password);
    newUser.email = user.email;

    try {
      await this.userRepository.save(newUser);
      return '注册成功';
    } catch (e) {
      this.logger.error(e, UserService);
      return '注册失败';
    }
  }

  generateRandomUsername() {
    const randomString = Math.random().toString(36).slice(2, 8);
    return '用户名' + randomString;
  }

  generateRandomNickName() {
    const randomString = Math.random().toString(36).slice(2, 8);
    return '昵称' + randomString;
  }

  //查询邮箱
  async findByEmail(email: any) {
    // 使用createQueryBuilder来构建查询
    return await this.userRepository
      .createQueryBuilder('user')
      .select(['user.id', 'user.username', 'user.password', 'user.email', 'user.status'])
      .where('user.email = :email', { email })
      .getOne();
  }

  //查询邮箱
  async findByPhone(phoneNumber: any) {
    return await this.userRepository
      .createQueryBuilder('user')
      .select(['user.id', 'user.username', 'user.password', 'user.phoneNumber', 'user.status'])
      .where('user.phoneNumber = :phoneNumber', { phoneNumber })
      .getOne();
  }

  // 创建用户
  async createUser(userData: CreateUserDto) {
    const { email } = userData;
    const existUser = await this.findByEmail(email);
    if (existUser) {
      throw new CustomException(ErrorCode.ERR_10006);
    }
    const { phoneNumber } = userData;
    const userPhone = await this.findByPhone(phoneNumber);
    if (userPhone) {
      throw new CustomException(ErrorCode.ERR_10007);
    }
    userData.password = md5(userData.password);
    await this.userRepository.save(userData);
    return '用户创建成功';
  }

  // 刷新用户信息
  async refreshUserInfo(userId: number) {
    const userData = await this.findUserById(userId);
    let currentRole = null;
    let userPermissionIds = [];
    if (userData.roles && userData.roles.length > 0) {
      if (!userData.lastRoleCode) {
        userData.lastRoleCode = userData.roles[0].roleCode;
        await this.userRepository.update({ id: userId }, { lastRoleCode: userData.lastRoleCode });
      }
      const selectedRole = userData.roles.find(
        (item: any) => item.roleCode === userData.lastRoleCode,
      );
      if (!selectedRole) {
        currentRole = userData.roles[0];
        await this.userRepository.update({ id: userId }, { lastRoleCode: currentRole.roleCode });
      } else {
        currentRole = selectedRole;
      }
      // 获取当前角色的权限
      if (currentRole) {
        userPermissionIds = await this.permissionService.getPermissionIdsByRoleCode(
          currentRole.roleCode,
        );
      }
    }
    const userInfo = {
      userId: userData.id,
      username: userData.username,
      nickName: userData.nickName,
      birthdayDate: userData.birthdayDate,
      avatar: userData.headPic,
      phoneNumber: userData.phoneNumber,
      email: userData.email,
      roles: userData.roles || [],
      currentRole: currentRole || {},
      permissionIds: userPermissionIds || [],
    };
    // 将用户信息存入redis
    await this.redisService.set(`USER_INFO:${userId}`, JSON.stringify(userInfo));
    return true;
  }

  // 根据用户ID查询用户
  async findUserById(userId: number) {
    const user = await this.userRepository
      .createQueryBuilder('user')
      .select([
        'user.id',
        'user.username',
        'user.nickName',
        'user.headPic',
        'user.phoneNumber',
        'user.gender',
        'user.email',
        'user.birthdayDate',
        'user.lastRoleCode',
        'user.lastLoginTime',
        'user.lastLoginIp',
        'user.status',
      ])
      // 选择状态为启用的角色 1为启用，0为禁用
      .leftJoin('user.roles', 'role', 'role.status = 1')
      .addSelect(['role.id', 'role.roleName', 'role.roleCode'])
      .where('user.id = :userId', { userId })
      .getOne();
    if (user && user.roles) {
      const roles = user.roles.map((role) => ({
        id: role.id,
        roleCode: role.roleCode,
        roleName: role.roleName,
      }));
      delete user.roles;
      return {
        ...user,
        roles,
      };
    }
    return user;
  }

  // 更新用户登录信息
  async updateUserLoginInfo(id: any, req: any) {
    const ip = req.ip.replace('::ffff:', '');
    await this.userRepository.update(id, {
      lastLoginTime: new Date(),
      lastLoginIp: ip,
    });
  }

  // 刷新所有在线用户的权限
  async refreshAllOnlineUserPermission() {
    const pattern = 'USER_INFO:*';
    const keys = await this.redisService.scan(pattern);
    const userIds = keys
      .map((key) => {
        const parts = key.split(':');
        return parts.length > 1 ? parts[1] : null;
      })
      .filter((userId) => userId !== null);
    if (userIds.length === 0) {
      return;
    }
    for (const userId of userIds) {
      await this.refreshUserInfo(Number(userId));
    }
    return;
  }

  // 禁用用户
  async switchAccountStatus(id: number) {
    const user = await this.userRepository.findOne({ where: { id } });
    if (!user) {
      throw new CustomException(ErrorCode.ERR_10005);
    }
    user.status = !user.status;
    await this.userRepository.save(user);
    return;
  }

  // 获取用户信息
  async getUserInfo(user: any) {
    try {
      let userInfo = await this.redisService.get(`USER_INFO:${user.userId}`);
      if (userInfo) {
        return JSON.parse(userInfo);
      } else {
        await this.refreshUserInfo(user.userId);
        userInfo = await this.redisService.get(`USER_INFO:${user.userId}`);
        return JSON.parse(userInfo);
      }
    } catch (error) {
      console.error('获取用户信息失败', error);
      throw new Error('无法获取用户信息');
    }
  }

  // 修改用户
  async updateUser(id: number, user: UpdateUserDto) {
    const findUser = await this.userRepository.findOne({ where: { id } });
    const newUser = this.userRepository.merge(findUser, user);
    await this.userRepository.save(newUser);

    // if (user.roleIds) {
    //   await this.updateUserRoles(id, { roleIds: user.roleIds });
    // }

    return true;
  }

  async offlineUser(id: number) {
    const user = await this.userRepository.findOne({ where: { id } });
    if (!user) {
      throw new CustomException(ErrorCode.ERR_11009);
    }
    // 先查询用户是否在线
    const accessToken = await this.redisService.get(`USER_ACCESS_TOKEN:${user.id}`);
    if (accessToken) {
      // 如果用户在线，删除用户的访问令牌
      await this.redisService.del(`USER_ACCESS_TOKEN:${user.id}`);
      return true;
    }
    throw new CustomException(ErrorCode.ERR_11009);
  }

  // 获取用户列表
  async getUserList(query: GetUserDto) {
    const { username, gender, role, status } = query;
    const pageSize: number = Number(query.pageSize) || 10;
    const pageNo: number = Number(query.pageNo) || 1;
    const [list, total] = await this.userRepository
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.roles', 'role')
      .where(username ? 'user.username LIKE :username' : '1=1', { username: `%${username}%` })
      .andWhere(gender ? 'user.gender = :gender' : '1=1', { gender })
      .andWhere(role ? 'role.id = :roleId' : '1=1', { roleId: role })
      .andWhere(status ? 'user.status = :status' : '1=1', { status })
      .skip((pageNo - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

    return {
      list,
      total,
      pageNo,
      pageSize,
    };
  }

  //更新用户角色
  async updateUserRoles(id: number, rolesDto: AddUserRolesDto): Promise<boolean> {
    return new Promise(async (resolve, reject) => {
      try {
        // 查询用户是否存在
        const user = await this.userRepository.findOne({ where: { id }, select: ['id'] });
        if (!user) {
          // 如果用户不存在，使用 Promise.reject
          return reject(new CustomException(ErrorCode.ERR_11006));
        }
        if (rolesDto.roleIds !== undefined) {
          // 查询角色是否存在且状态是否启用
          const roles = await this.roleRepository.find({
            where: { id: In(rolesDto.roleIds), status: true },
          });
          // 如果查询到的角色数量和传入的角色ID数量不一致，说明有角色不存在或未启用
          if (roles.length !== rolesDto.roleIds.length) {
            return reject(new CustomException(ErrorCode.ERR_40001));
          }
          user.roles = roles;
        }
        await this.userRepository.save(user);
        resolve(true);
      } catch (err) {
        reject(err);
      }
    });
  }

  // 重置密码
  async resetPassword(id: number, password: UpdatePasswordDto) {
    const user = await this.userRepository.findOne({ where: { id } });
    user.password = md5(password.password);
    await this.userRepository.save(user);
    return true;
  }

  // 删除用户
  async deleteUser(id: number) {
    if (id === 1) {
      throw new HttpException('超级管理员不可删除', HttpStatus.BAD_REQUEST);
    }
    await this.userRepository.softDelete(id);
    return true;
  }

  // 获取系统当前在线用户列表
  async getOnlineUserList() {
    const pattern = 'USER_ACCESS_TOKEN:*';
    const keys = await this.redisService.scan(pattern);
    const userIds = keys
      .map((key) => {
        const parts = key.split(':');
        return parts.length > 1 ? parts[1] : null;
      })
      .filter((userId) => userId !== null);

    if (userIds.length === 0) {
      return [];
    }
    return await this.userRepository
      .createQueryBuilder('user')
      .select([
        'user.id',
        'user.username',
        'user.phoneNumber',
        'user.email',
        'user.status',
        'user.headPic',
        'user.lastLoginTime',
        'user.lastLoginIp',
      ])
      .where('user.id IN (:...userIds)', { userIds })
      .getMany();
  }
}
